exports.Headers.encode   A
last analyzed

Complexity

Conditions 1
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 8
rs 9.4285

1 Function

Rating   Name   Duplication   Size   Complexity  
A 0 5 1
1
/**
2
 * @module http/_common
3
 */
4
5
var Schema = require('./_schema')
6
7
/**
8
 * Simple inheritance establisher
9
 *
10
 * @param parent
11
 * @param child
12
 * @param name
13
 */
14
function extend (parent, child, name) {
15
  child.prototype = Object.create(parent.prototype)
16
  child.prototype.constructor = child
17
  child.prototype.name = name
18
}
19
20
function NetworkException (message, code, request) {
21
  this.message = message || this.message
22
  this.code = code || this.code
23
  this.request = request
24
  this.stack = new Error().stack
25
}
26
extend(Error, NetworkException, 'NetworkException')
27
var N = NetworkException
28
N.prototype.code = -1
29
N.prototype.message = 'Unexpected exception during request'
30
31
var index = {
32
  '-1': N
33
}
34
35
/**
36
 * @class {IllegalUrlException}
37
 *
38
 * @property {string} message
39
 * @property {int} code
40
 */
41
42
/**
43
 * @class {MissingHostException}
44
 *
45
 * @property {string} message
46
 * @property {int} code
47
 */
48
49
/**
50
 * @class {ConnectionErrorException}
51
 *
52
 * @property {string} message
53
 * @property {int} code
54
 */
55
56
/**
57
 * @class {RedirectVortexException}
58
 *
59
 * @property {string} message
60
 * @property {int} code
61
 */
62
63
/**
64
 * @class {NetworkErrorException}
65
 *
66
 * @property {string} message
67
 * @property {int} code
68
 */
69
70
/**
71
 * @class {TimeoutException}
72
 *
73
 * @property {string} message
74
 * @property {int} code
75
 */
76
77
/**
78
 * @class {VoxEngineErrorException}
79
 *
80
 * @property {string} message
81
 * @property {int} code
82
 */
83
84
/**
85
 * @namespace
86
 *
87
 * @property {Function} IllegalUrlException
88
 * @property {Function} MissingHostException
89
 * @property {Function} ConnectionErrorException
90
 * @property {Function} RedirectVortexException
91
 * @property {Function} NetworkErrorException
92
 * @property {Function} TimeoutException
93
 * @property {Function} VoxEngineErrorException
94
 */
95
var exports = {
96
  NetworkException: N,
97
  codeExceptionIndex: index,
98
  Method: Schema.Method
99
}
100
101
/**
102
 * Declares new NetworkException (resembling VoxImplant HTTP client
103
 * negative response codes)
104
 *
105
 * @param {string} name Exception name
106
 * @param {int} code Exception code (response code)
107
 * @param {string} message Default exception message
108
 */
109
function declare (name, code, message) {
110
  var e = function () {
111
    N.apply(this, arguments)
112
  }
113
  extend(N, e, name)
114
  e.prototype.constructor = e
115
  e.prototype.code = e.code = code
116
  e.prototype.message = message
117
  exports[name] = e
118
  index[code] = e
119
}
120
121
declare('IllegalUrlException', -2, 'Illegal URL exception')
122
declare('MissingHostException', -3, 'Could not find host')
123
declare('ConnectionErrorException', -4, 'Could not establish connection')
124
declare('RedirectVortexException', -5, 'Too many redirects')
125
declare('NetworkErrorException', -6, 'Network error exception')
126
declare('TimeoutException', -7, 'Request timeout exceeded')
127
declare('VoxEngineErrorException', -8, 'Internal exception during request')
128
129
function HttpException (message, request, response) {
130
  this.message = message
131
  this.request = request
132
  this.response = response
133
  this.stack = new Error().stack
134
}
135
extend(Error, HttpException, 'HttpException')
136
exports.HttpException = HttpException
137
138
function ServerErrorException () {
139
  HttpException.apply(this, arguments)
140
}
141
extend(HttpException, ServerErrorException, 'ServerErrorException')
142
exports.ServerErrorException = ServerErrorException
143
144
function ClientErrorException () {
145
  HttpException.apply(this, arguments)
146
}
147
extend(HttpException, ClientErrorException, 'ClientErrorException')
148
exports.ClientErrorException = ClientErrorException
149
150
function NotFoundException () {
151
  HttpException.apply(this, arguments)
152
}
153
extend(HttpException, NotFoundException, 'NotFoundException')
154
exports.NotFoundException = NotFoundException
155
156
function InvalidConfigurationException (message) {
157
  this.message = message || 'Invalid configuration'
158
  this.stack = new Error().stack
159
}
160
extend(Error, InvalidConfigurationException, 'InvalidConfigurationException')
161
exports.InvalidConfigurationException = InvalidConfigurationException
162
163
/**
164
 * Normalizes provided bag, ensuring that it's an object where every
165
 * key corresponds to value of array of strings
166
 *
167
 * @param bag
168
 * @return {Object}
169
 */
170
function normalize (bag) {
171
  bag = bag || {}
172
  Object.keys(bag).forEach(function (key) {
173
    if (!(bag[key] instanceof Array)) {
174
      bag[key] = [bag[key]]
175
    }
176
  })
177
  return bag
178
}
179
180
/** @deprecated */
181
exports.Params = {
182
  normalize: normalize
183
}
184
185
exports.Query = {
186
  /**
187
   * Encodes provided query to a url-safe string
188
   *
189
   * @param {Query} query
190
   * @returns {string}
191
   */
192
  encode: function (query) {
193
    query = normalize(query || {})
194
    return Object.keys(query).reduce(function (carrier, key) {
195
      return carrier.concat(query[key].map(function (value) {
196
        return encodeURIComponent(key) + '=' + encodeURIComponent(value)
197
      }))
198
    }, []).join('&')
199
  },
200
  normalize: normalize
201
}
202
203
exports.Headers = {
204
  /**
205
   * Encodes headers object to VoxEngine / protocol presentation
206
   *
207
   * @param {Headers} headers
208
   * @returns {string[]}
209
   */
210
  encode: function (headers) {
211
    headers = normalize(headers || {})
212
    return Object.keys(headers).reduce(function (_, k) {
213
      return _.concat(headers[k].map(function (v) {
214
        return k + ': ' + v
215
      }))
216
    }, [])
217
  },
218
  /**
219
   * Headers in VoxImplant come in key-value pairs:
220
   *
221
   * - key: Server
222
   *   value: nginx/1.9.9
223
   * - key: Link
224
   *   value: Wed, 09 Aug 2017 18:16:58 GMT
225
   * - key: Link
226
   *   value: <https://voximplant.com/>; rel="home"
227
   * - key: Link
228
   *   value: <https://voximplant.com/docs>; rel="documentation"
229
   *
230
   * ([reference](http://voximplant.com/docs/references/appengine/Net.HttpRequestResult.html))
231
   *
232
   * This method converts such pairs into an object with headers collected by
233
   * their key:
234
   *
235
   * Server:
236
   *   - nginx/1.9.9
237
   * Link:
238
   *   - <https://voximplant.com/>; rel="home"
239
   *   - <https://voximplant.com/docs>; rel="documentation"
240
   *
241
   * @param {Object[]} headers
242
   * @return {Headers}
243
   */
244
  decode: function (headers) {
245
    return (headers || []).reduce(function (carrier, item) {
246
      carrier[item.key] = carrier[item.key] || []
247
      carrier[item.key].push(item.value)
248
      return carrier
249
    }, {})
250
  },
251
252
  /**
253
   * Merges two or more headers definitions, using latter's values on
254
   * intersecting keys.
255
   *
256
   * @param {...Headers} args
257
   * @returns {Headers}
258
   */
259
  override: function (args) {
260
    return []
261
      .filter.call(arguments, function (_) { return _ })
262
      .reduce(function (carrier, _) {
263
        Object.keys(_).forEach(function (key) { carrier[key] = _[key] })
264
        return carrier
265
      }, {})
266
  },
267
  normalize: normalize
268
}
269
270
/** @deprecated */
271
exports.Headers.merge = exports.Headers.override
272
/** @deprecated */
273
exports.headers = exports.Headers
274
/** @deprecated */
275
exports.query = exports.Query
276
/** @deprecated */
277
exports.params = exports.Params
278
module.exports = exports
279